Repository navigation
fix(nativeaot): generate self-writing RPC responses - #11379
ReubenBond wants to merge 54 commits into
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Registration ordering, an inert public generation attribute, and partial dictionary comparer support introduce unresolved behavioral problems.
Review effort: Balanced
Findings: 3
Open (3)
What changed in this PR
Adds NativeAOT-safe, closed RPC response serializer/copier graphs and supporting static serializer-context infrastructure.
Changes:
- Generates closed response factories and strict diagnostics for concrete RPC results.
- Adds transactional factory resolution, explicit serializer contexts, and response codecs/copiers.
- Adds unit, source-generator, and NativeAOT smoke coverage.
| File | Description |
|---|---|
test/Orleans.Serialization.UnitTests/RpcResponseTests.cs |
Tests response codecs, copiers, factories, and invokables. |
test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj |
Links shared RPC smoke contracts. |
test/Orleans.NativeAotSmoke/RpcResponsesModels.cs |
Defines smoke RPC contracts and payload. |
test/Orleans.NativeAotSmoke/RpcResponses.smoke.json |
Configures strict RPC smoke diagnostics. |
test/Orleans.NativeAotSmoke/RpcResponses.cs |
Runs the native response smoke scenario. |
test/Orleans.NativeAotSmoke/RpcResponses.Contracts.cs |
Implements shared response serialization checks. |
test/Orleans.NativeAotSmoke/Orleans.NativeAotSmoke.csproj |
Defines the NativeAOT smoke project. |
test/Orleans.NativeAotSmoke/NativeAotEnvironment.cs |
Verifies execution without dynamic code. |
test/Orleans.NativeAotSmoke/Factories.cs |
Runs static factory smoke checks. |
test/Orleans.NativeAotSmoke/Factories.Contracts.cs |
Tests cyclic factory publication and rollback. |
test/Orleans.CodeGenerator.Tests/StaticSerializerFactoryTests.cs |
Exposes factory contracts as unit tests. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithMultipleInterfaces.verified.cs |
Updates generated response-factory snapshot. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithDifferentKeyTypes.verified.cs |
Updates generated response-factory snapshot. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithResponseTimeout.verified.cs |
Updates generated response-factory snapshot. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithInvokableBaseType.verified.cs |
Updates generated response-factory snapshot. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs |
Updates complex-result factory snapshot. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateMethodSerializersAnnotation.verified.cs |
Updates generated factory snapshot. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicGrain.verified.cs |
Updates basic response-factory snapshot. |
test/Orleans.CodeGenerator.Tests/OrleansSourceGeneratorTests.cs |
Tests factory generation and diagnostics. |
test/Orleans.CodeGenerator.Tests/Orleans.CodeGenerator.Tests.csproj |
Links shared factory contracts. |
src/Orleans.Serialization/TypeSystem/SerializerContextTypeResolver.cs |
Resolves only context-registered types. |
src/Orleans.Serialization/Serializers/CodecProvider.cs |
Adds static factory lookup and transactional caching. |
src/Orleans.Serialization/SerializerContext.cs |
Introduces the serializer-context base class. |
src/Orleans.Serialization/Invocation/Response.cs |
Adds concrete response codec/copier implementations. |
src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs |
Adds serializer-context DI registration. |
src/Orleans.Serialization/Hosting/SerializerBuilderExtensions.cs |
Adds builder-level context registration. |
src/Orleans.Serialization/GeneratedCodeHelpers/OrleansGeneratedCodeHelper.cs |
Resolves statically registered services. |
src/Orleans.Serialization/Configuration/TypeManifestOptions.cs |
Adds closed serializer and service factories. |
src/Orleans.Serialization/Codecs/DictionaryCodec.cs |
Adds a default-comparer constructor. |
src/Orleans.Serialization.Abstractions/Orleans.Serialization.Abstractions.csproj |
Marks supported targets as AOT-compatible. |
src/Orleans.Serialization.Abstractions/GenerateSerializerContextAttribute.cs |
Introduces serializer-context generation metadata. |
src/Orleans.CodeGenerator/SourceGeneratorOptionsParser.cs |
Parses response-factory validation options. |
src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs |
Builds closed serialization dependency graphs. |
src/Orleans.CodeGenerator/RpcResponseGenerator.cs |
Generates closed RPC response factories. |
src/Orleans.CodeGenerator/Resources.resx |
Adds the response-factory diagnostic text. |
src/Orleans.CodeGenerator/OrleansSourceGenerator.cs |
Integrates response generation into the pipeline. |
src/Orleans.CodeGenerator/Diagnostics/DiagnosticRuleId.cs |
Defines diagnostic ORLEANS0116. |
src/Orleans.CodeGenerator/build/Microsoft.Orleans.CodeGenerator.props |
Exposes AOT validation build properties. |
src/Orleans.CodeGenerator/AnalyzerReleases.Unshipped.md |
Records the new diagnostic. |
src/api/Orleans.Serialization/Orleans.Serialization.cs |
Updates the generated serialization API surface. |
src/api/Orleans.Serialization.Abstractions/Orleans.Serialization.Abstractions.cs |
Updates the abstractions API surface. |
docs/site/src/content/docs/implementation/serialization.md |
Documents closed RPC response factories. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Native response serialization omits completion and exception codecs, context generation is not implemented, and serializer setup is order-dependent.
Review effort: Balanced
Findings: 1
Open (4)
Resolved since last review (1)
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Serializer setup is order-dependent, the context attribute has no generator implementation, and special response codecs remain unregistered.
Review effort: Balanced
Findings: 1
Open (3)
Resolved since last review (1)
Code coverage
Report-only conclusion: current-main baseline stale. The newest successful coverage run tested c572586, not current main 48f3aaa. Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities. The comparison remains report-only while normal line and branch variance is calibrated. Coverage details |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Registration order can omit default services, and strict NativeAOT graphs cannot serialize completed or exception responses.
Review effort: Balanced
Findings: 1
Open (2)
Resolved since last review (1)
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The strict generated response context cannot serialize completed or exception responses despite registering the polymorphic Response codec.
Review effort: Balanced
Findings: 1
Resolved since last review (1)
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
It substantially changes serializer resolution, concurrent factory publication, public APIs, and NativeAOT code generation across the runtime.
Review effort: Balanced
Findings: None
Resolved since last review (1)
Record canonical service aliases independently of registration order and declare the exact services consumed by inferred factories. Preserve contract-aware parents and custom metadata precedence. Emit RPC registrations unconditionally and retain managed/native/framework-symbol source parity.
Share candidate constraint validation, source-known argument metadata, immutable response plans, and construction-driven registration emission. Remove redundant manifest maps and pair each closed factory with its service identity. Centralize response copy/dispose ownership and raw reader adaptation while retaining typed/runtime dispatch, filter isolation, graph publication, and native-safe factory selection.
Register source-known metadata for constructor-constrained targets and apply the generator layout required by CI.
Move InvokeAndCopy onto IInvokable, share request/stage/response lifetime in GrainCallInvoker, and remove the copy-boundary and ownership wrappers. Preserve original exceptions through filters and copy exception envelopes at delivery.
Read an initialized published serializer service before constructing another graph scope. Keep admission and fault checks, and isolate the allocating factory closure on the cold path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Borrow a cleared, bounded per-thread visited set without caching admission decisions. Preserve provider-specific overrides and graph boundaries while removing 176 bytes from each warmed default-service lookup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Retain provider-scoped transactional factory resolution and constructor compatibility checks instead of repeating four codec/copier lookups on every invocation. Cover cold initialization and retry, warmed zero-allocation resolution, overrides, canonical identities, rollback, fault propagation and NativeAOT publication. Regenerate both framework snapshots. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2fd2ecd7-0e1d-4526-b715-71eff94612a5
Use a shared InvocationContext with generated synchronous completion and concrete async slow paths. Centralize compatibility adaptation in non-generic code, remove delegate-based response release dispatch, and unify pools by envelope type. Preserve construction-only dependency resolution, service precedence, exception timing and consuming ownership.
…target Apply new()-constraint abstract-type rejection before generic closure on all supported frameworks. Cover metadata-free and captured selection, fallback identity and pending construction without attempting the rejected closure.


Fixes #11375.
Native RPC response handling selected pooled codecs and copiers by closing open generic implementations at runtime. Generate concrete, non-generic response holders and closed construction graphs for source-known method results and proxy dependencies.
The generator emits identical invocation and registration code for managed and NativeAOT publishing. Closed factories participate through the common provider resolution pipeline, with application registration precedence selecting services in either execution mode. Full emitted-source parity covers result models, collections, primitive responses, completion responses, and explicit serializer contexts.
IInvokable.Invoke(InvocationContext)is the common invocation contract. Runtime clients and observers reuse a context containing their provider-owned serialization services. Generated implementations invoke concrete targets, isolate successful results, and rent concrete holders directly. Completed tasks and value tasks use a synchronous entry; pending results use a concrete asynchronous completion method. Non-generic runtime code supplies compatibility adaptation and envelope release, preserving custom codec/copier selection and same-instance copier results. Response pools share one implementation keyed by the actual envelope type.Response factory dependencies resolve and undergo compatibility checks during construction. Warmed invocations retain provider-scoped transactional factory resolution, with allocation-free published lookup and reused admission traversal storage.
Exceptions remain original through filters and are copied at delivery. A shared
GrainCallInvokersupplies request metadata, filter-stage progression, and response lifetime for incoming and outgoing calls. It retains selected and superseded envelopes through filter continuations, supports restoring earlier selections, and releases owned envelopes exactly once.Completion takes ownership of its response input. Typed completion extracts the payload and releases the envelope; untyped completion transfers a successful envelope to its consumer. Void consumption and completed outgoing filter chains release their envelopes. Messages release response bodies on successful writes, terminal disposal, and replacement while retaining them during actual retries. Explicit callback handoffs clear the message's ownership before completion.
IRawResponseWriterwrites the existing raw protocol directly before the sender queries a response codec. ClosedIRawResponseReaderregistrations reconstruct holders from the wire result type. Direct holders/readers require exact canonical response codec and copier types; custom subclasses preserve their raw wire and copying behavior through compatibility dispatch. Primitive codecs, reference cycles, shared identity, pool reset, completion responses, exceptions, and custom implementation selection retain their established semantics.Inferred defaults use the existing metadata selector and complete constructor dependency descriptors. Admission validates bound generic constraints before comparing implementation identities, using generated closed argument metadata. Automatic metadata construction retains its ordinary dependency-injection boundary throughout the call chain; inferred default leaves participate in an existing closed transaction or start a transaction as a closed root. Explicit child registrations and selected converter contracts retain precedence throughout canonical codec, copier, and activator aliases.
The combined inferred response graph admits up to 1,024 closed executable types. Aggregate failures report ORLEANS0116 in managed and native builds while retaining holder declarations. Argument failures provide argument-specific guidance, including for one-way contracts. Every response-returning RPC emits the shared non-generic
Responsegraph independently of automatic result admission, allowing explicit-only dictionary and runtime-selected generic result contracts to use runtime response dispatch.Explicit serializer contexts and inferred RPC response graphs share the graph collector, constructor inspection, provider-owned construction scopes, and metadata registration contracts merged into
main. NativeAOT targets .NET 10+, with actual managed .NET 8 compatibility retained. Native coverage uses the shared smoke project and centralized runner.Draft remains held for fresh CI and final human review.
Microsoft Reviewers: Open in CodeFlow